package com.aceitunaproject.clientinterface;

import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.aceitunaproject.clientinterface.eventadapters.*;
import com.aceitunaproject.clientinterface.eventregistering.*;
import com.aceitunaproject.clientinterface.listener.DefaultListener;
import com.aceitunaproject.shared.message.*;
import com.aceitunaproject.shared.message.concrete.*;

/**
 * @author Federico Bergstein
 * 
 *         An implementation of Aceituna's Client-Server interface
 */
public class AceitunaClientInterfaceImpl implements AceitunaClientInterface {

	/** the name of the player */
	private String player;

	AceitunaConnectionEventsHandler connectionEventsHandler;
	HashMap<String, AceitunaEventAdapter> eventAdaptersMap = new HashMap<String, AceitunaEventAdapter>();

	private DefaultListener listener;
	Logger logger = Logger.getLogger(this.getClass().getName());

	public AceitunaClientInterfaceImpl(String playerName) {
		listener = new DefaultListener(this);
		player = playerName;
		// TODO: consider getting the map from some initializer or another, more
		// generic, solution
		eventAdaptersMap.put(ChatMessageReceivedEvent.TYPE,
				new ChatMessageReceivedAdapter());
		eventAdaptersMap.put(MapAreaRefreshEvent.TYPE,
				new MapAreaRefreshAdapter());
		eventAdaptersMap.put(RuleViolationEvent.TYPE,
				new RuleViolationEventReceivedAdapter());

	}
	
	public AceitunaClientInterfaceImpl() {
		listener = new DefaultListener(this);
		//player = playerName;
		// TODO: consider getting the map from some initializer or another, more
		// generic, solution
		eventAdaptersMap.put(ChatMessageReceivedEvent.TYPE,
				new ChatMessageReceivedAdapter());
		eventAdaptersMap.put(MapAreaRefreshEvent.TYPE,
				new MapAreaRefreshAdapter());
		eventAdaptersMap.put(RuleViolationEvent.TYPE,
				new RuleViolationEventReceivedAdapter());

	}
	

	public void login() {
		listener.login();
	}

	public void registerForConnectionEvents(
			AceitunaConnectionEventsHandler handler) {

		connectionEventsHandler = handler;
	}

	public void registerToEvent(AceitunaAllEventsHandler handler) {

		registerToEvent((ChatMessageReceivedHandler) handler);
		registerToEvent((MapAreaRefreshHandler) handler);
		registerToEvent((RuleViolationEventReceivedHandler) handler);
	}

	public void registerToEvent(ChatMessageReceivedHandler handler) {
		eventAdaptersMap.get(ChatMessageReceivedEvent.TYPE).getHandlers().add(
				handler);

	}

	public void registerToEvent(MapAreaRefreshHandler handler) {
		eventAdaptersMap.get(MapAreaRefreshEvent.TYPE).getHandlers().add(
				handler);

	}

	public void registerToEvent(RuleViolationEventReceivedHandler handler) {
		eventAdaptersMap.get(RuleViolationEvent.TYPE).getHandlers()
				.add(handler);

	}

	public String getPlayer() {

		return player;
	}

	public void moveUnit(Long unitID, int x, int y) {
		MoveRequest moveRequest = new MoveRequest();
		moveRequest.setElement(unitID);
		moveRequest.setDestinationX(x);
		moveRequest.setDestinationY(y);
		listener.sendObjectMessage(moveRequest);

	}

	public void requestMapRefresh() {
		listener.sendObjectMessage(new MapAreaRefreshRequest());

	}

	public void processMessage(Message deserializedMessage) {

		AceitunaEventAdapter adapter = eventAdaptersMap.get(deserializedMessage
				.getMessageType());

		if (adapter == null) {
			logger.log(Level.WARNING, "Unrecognized message type received");
		} else {
			adapter.trigger(deserializedMessage);
		}
	}

	public void sendMessage(Message message) {
		listener.sendObjectMessage(message);

	}

	public void disconnected(boolean arg0, String arg1) {
		logger.log(Level.WARNING, "Disconnected");
		// TODO: log arguments, investigate if the boolean is the Gracefully
		// flag
		if (connectionEventsHandler != null) {
			connectionEventsHandler.disconnected(arg0, arg1);
		}
	}

	public void loggedIn() {
		logger.fine("logged In");
		if (connectionEventsHandler != null) {
			connectionEventsHandler.loggedIn();
		}
	}

	public void loginFailed(String arg0) {
		logger.log(Level.WARNING, "Login Failed with args " + arg0);
		if (connectionEventsHandler != null) {
			connectionEventsHandler.loginFailed(arg0);
		}
	}

	public void reconnected() {
		logger.fine("reconnected");
		if (connectionEventsHandler != null) {
			connectionEventsHandler.reconnected();
		}

	}

	public void reconnecting() {
		logger.fine("reconnecting");
		if (connectionEventsHandler != null) {
			connectionEventsHandler.reconnecting();
		}

	}

	public void logout() {
		listener.logout();
	}

	public void buildSettlement(Long unitID, String name, int x, int y) {
		BuildSettlementRequest settlementRequest = new BuildSettlementRequest();
		settlementRequest.setElement(unitID);
		settlementRequest.setName(name);
		settlementRequest.setPositionX(x);
		settlementRequest.setPositionY(y);
		listener.sendObjectMessage(settlementRequest);

	}

	public void buildInstallation(Long unitID, String name, int x, int y,
			String installationType) {
		BuildInstallationRequest installationRequest = new BuildInstallationRequest();
		installationRequest.setElement(unitID);
		installationRequest.setName(name);
		installationRequest.setPositionX(x);
		installationRequest.setPositionY(y);
		installationRequest.setInstallationType(installationType);
		listener.sendObjectMessage(installationRequest);

	}

	public void recruitUnit(Long settlementID, String name, int persons) {
		RecruitUnitRequest request = new RecruitUnitRequest();
		request.setElement(settlementID);
		request.setName(name);
		request.setPersons(persons);
		sendMessage(request);
		
	}

	public void attackUnit(Long attackingUnitID, Long enemyUnitID) {
		AttackRequest request = new AttackRequest();
		request.setElement(attackingUnitID);
		request.setEnemyUnitId(enemyUnitID);
		sendMessage(request);
		
	}

	public void setPlayer(String userName) {
		this.player = userName;
		
	}
}
